package com.kk.datastructure.linkedlist;

/**
 * title: 单链表案例
 * @author 阿K
 * 2020年11月22日 下午7:41:20 
 */
public class SingleLinkedListDemo {

	public static void main(String[] args) {
		//先创建节点
		HeroNode hero1 = new HeroNode(1, "宋江", "及时雨");
		HeroNode hero2 = new HeroNode(2, "卢俊义", "玉麒麟");
		HeroNode hero3 = new HeroNode(3, "吴用", "智多星");
		HeroNode hero4 = new HeroNode(4, "林冲", "豹子头");
		
		//创建要给链表
		SingleLinkedList singleLinkedList = new SingleLinkedList();
		
		singleLinkedList.addByOrder(hero1);
		singleLinkedList.addByOrder(hero4);
		singleLinkedList.addByOrder(hero2);
		singleLinkedList.addByOrder(hero3);
		
		singleLinkedList.addByOrder(hero3);
		
		
		//加入
//		singleLinkedList.add(hero1);
//		singleLinkedList.add(hero4);
//		singleLinkedList.add(hero2);
//		singleLinkedList.add(hero3);
		
		singleLinkedList.list();

	}

}

//定义HeroNode ， 每个HeroNode 对象就是一个节点
class HeroNode {
	public int no;		   // 好汉排行
	public String name;	   // 好汉姓名
	public String nickname;// 好汉外号
	public HeroNode next;  //指向下一个节点（好汉）
	//构造器
	public HeroNode(int no, String name, String nickname) {
		this.no = no;
		this.name = name;
		this.nickname = nickname;
	}
	//为了显示方法，我们重新toString
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
	}
	
}

// 定义 SingleLinkedList 管理梁山英雄
class SingleLinkedList{
	// 先初始化一个头节点,头节点不能动,不存放具体的数据（可以理解为王伦 -- 初代寨主，后被林冲捅了）
	private HeroNode head = new HeroNode(0, null, null);
	
	// 返回头结点
	public HeroNode getHead() {
		return head;
	}
	
	// 添加节点到单向链表
	// 思路，当不考虑编号顺序时
	// 1. 找到当前链表的最后节点
	// 2. 将最后这个节点的next 指向 新的节点
	public void add(HeroNode heroNode) {
		// 因为head节点不能动，因此我们需要一个辅助变量 temp（可以理解为晁天王）
		HeroNode temp = head;
		// 遍历链表，找到最后
		while(true) {
			// 找到链表的最后是null	
			if(temp.next == null)break;
			// 若没有找到最后，则后移(这里是n+1次的，n个有效数据)
			temp = temp.next;
		}
		// 当退出while循环时，temp就指向了链表的最后
		// 将最后这个节点的next 指向 新的节点
		temp.next = heroNode;				
	}
	
	// 按编号顺序添加（如果有这个排名，则添加失败，并给出提示）
	public void addByOrder(HeroNode heroNode) {
		// 因为头节点不能动，因此我们仍然通过一个辅助指针(变量)来帮助找到添加的位置
		// 因为单链表，因为我们找的temp 是位于 添加位置的前一个节点，否则插入不了
		HeroNode temp = head;
		boolean flag = false;// flag标志添加的编号是否存在，默认为false
		while(true) {
			if(temp.next == null) break;
			if(temp.next.no > heroNode.no)
				// 位置找到，就在 temp后面
				// 因为 它满足了 按顺序 ，所以可以插入
				break;
			if(temp.next.no == heroNode.no) {
				// 已经存在改排行的编号(不可重复)
				flag = true;
				break;
			}
			// 没满足以上，后移下一次节点继续找
			temp = temp.next;
		}
		
		// 对 flag 进行判断
		if(flag) 
			// 不能添加，说明编号已经存在
			System.out.printf("准备插入的英雄的编号 %d 已经存在了, 不能加入\n", heroNode.no);
		else {
			// 插入到链表中，temp的后面
			heroNode.next = temp.next;// 我后面的是6号，现在你后面是6号
			temp.next = heroNode;// 我后面是你
		}
	}
	
	// 遍历链表
	public void list() {
		// 判断链表是否为空
		if (head.next == null) {
			System.out.println("链表为空~~~");
			return;
		}
		// 因为头节点，不能动，因此我们需要一个辅助变量来遍历
		HeroNode temp = head.next;

		while (true) {
			// 判断是否到链表的最后
			if (temp == null)
				return;

			// 输出节点信息
			System.out.println(temp);
			// 将节点后移，注意要加！！
			temp = temp.next;
		}
	}
}
